package ru.ncedu.java.tasks;

/**
 * Комментарии к классу после импортов на английском языке
 *
 * Класс, реализующий запуск Калькулятора
 * @author dalas
 *
 */

import ru.ncedu.java.tasks.operations.Operation;

import java.util.HashMap;
import java.util.Set;

public class TestCalculator {

	public static void main(String args[]) throws InstantiationException, IllegalAccessException {
		System.out.println("Запуск программы...");
		
		// Создаем хеш-карту для сохранения данных с XML-файла
		HashMap<String, String> hm = new HashMap<String, String>();  //Не желательно так Map создавать.
//		Map<String, String> hm = new HashMap<String, String>();     //Либо так
//		Map<String, String> hm = new HashMap<>();                   //Либо так (можно с Java 1.7)
		
		// Парсим XM
		/* Зачем в верху Map создавал. Лишняя операция по созданию занимающая время. Можно заменить на:
		 Map<String, String> hm = Parser.parse("src\\ru\\ncedu\\java\\tasks\\Operations.xml");
		 Переменные называй нормально не понятно, что хранит в себе переменная hm, если дальше не прочитать код.
		 Представь себя на месте человека, который будет читать такой код
		 */
		hm = Parser.parse("src\\ru\\ncedu\\java\\tasks\\Operations.xml");
		
		System.out.println("Парсинг XML-файла проведен успешно...");

		//Нужна проверка что у тебя мапа не пустая и в ней есть какие-то операции, если пустая просьба добавить операцию
		//в xml файл и ее реализацию
		// Получим набор ключей
		Set<String> keys = hm.keySet();
		
		// Начинаем работу
		System.out.println("Калькулятор запущен!");
		
		
		// а, b - переменные-операнды
		double a=0, b=0;                             // Каждое объявление переменной с новой строки
		// globalResult хранит текущий результат
		double globalResult=0;
		// Указатель на класс операции
		Operation op=null;
		// Условие завершения работы программы
		boolean bool = true;
		// Переменная принимает значение false после первого вызова операции
		boolean firstTime = true;
		
		// Начинаем цикл
		do {
			String checkInData = null;
			String className = null;
			start: {
				// Блок первичного ввода
				firstOperand: {
				
					String inData1;
					do {
						// System.out.println("Блок first!!!"); 
						inData1 = Input.run(keys);
						
						// Выход из цикла
						if (inData1.equals("exit")) {
							bool = false;
							break start;
						}
						
						// Если после полученного результата вводим операцию, то сразу считаем
						if (inData1.equals("operation") & !firstTime) {
							checkInData = inData1;
							a = globalResult;
							break firstOperand;
						} 
						
						// Если ввели число, запоминаем его как первый операнд
						if (inData1.equals("number")) {
							a = Double.parseDouble(Input.value);
							//System.out.println(a);
							break firstOperand;
						} else {
							// "Защита от дурака"
							System.out.println("Введите операнд!");
						}
					// Цикл продолжается, пока пользователь не введет корректные данные	
					} while (!inData1.equals("number"));
				}
				
				Operation: {
					String inData2;
					
					do {
						//System.out.println("Блок Operation!!!");
						
						// Проверка вычисления результата (т.е. результат - первый операнд)
						if (checkInData != null) {
							inData2 = checkInData;
						} else {
							inData2 = Input.run(keys);
						}
						
						// Выход из цикла
						if (inData2.equals("exit")) {
							bool = false;
							break start;
						}
						
						// Проводим вычисления
						if (inData2.equals("operation")) {
							// Переменная firstTime перестает быть true
							firstTime = false;
							Class cl;
							try {
								// Загружаем соответствующий класс
								cl = Class.forName(hm.get(Input.value));
								// Запоминаем имя класса
								className = cl.getName();
								op = (Operation)cl.newInstance();
								
								//System.out.println(className);
								// System.out.println(op.type());
								
								// Если операция унарная, то проводим вычисления
								if (op.type().equals("unary")) {
									System.out.println(op.result(a, a));
									globalResult = op.result(a, a);
									break start; 
								}
								
								// Если операция бинарная, то переходим в следующий блок
								if (op.type().equals("binary")) {
									break Operation;
								}
								
								
							} catch (ClassNotFoundException e) {
								// TODO Auto-generated catch block            // Удалить
								e.printStackTrace();                          // Нормальная обработка исключения
							}
							
							break Operation;
						} else {
							// "Защита от дурака"
							System.out.println("Введите операцию!");
						}
					// Цикл продолжается, пока пользователь не введет корректные данные		
					} while (!inData2.equals("operation"));
				}
				
				secondOperand: {
					String inData1;
					do {
						// System.out.println("Блок second!!!");
						inData1 = Input.run(keys);
						
						if (inData1.equals("exit")) {
							bool = false;
							break start;
						}
						
						if (inData1.equals("number")) {
							
							b = Double.parseDouble(Input.value);
							// System.out.println(b);
							// Считаем, выводим и запоминаем результат
							
							if (className.equals("ru.ncedu.java.tasks.operations.Division") & b == 0.0) {
								System.out.println("Нельзя делить на ноль!");
							} else {
								System.out.println(op.result(a, b));
								globalResult = op.result(a, b);
								break secondOperand;
							}
						} else {
							// "Защита от дурака"
							System.out.println("Введите операнд!");
						}
					// Цикл продолжается, пока пользователь не введет корректные данные	
					} while (!inData1.equals("number"));
				}
			}
		} while(bool);
			
		System.out.println("Завершение работы!");

	}
}



